package de.tum.control;

import android.app.Activity;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;

/**
 * This class provides the functionality of advanced gesture events such as onSwipe and onPinchZoom.
 *
 */
public class GestureFilter extends SimpleOnGestureListener{

	 public final static int SWIPE_UP    = 1;
	 public final static int SWIPE_DOWN  = 2;
	 public final static int SWIPE_LEFT  = 3;
	 public final static int SWIPE_RIGHT = 4;
	 public final static int SWIPE_TOPLEFT = 5;
	 public final static int SWIPE_TOPRIGHT = 6;
	 public final static int SWIPE_BOTTOMLEFT = 7;
	 public final static int SWIPE_BOTTOMRIGHT = 8;
	
	static final int NONE = 0;
	static final int ZOOM = 1;
	static final float min_dist = 100; 
	int mode = NONE;
	
	double oldDist, newDist, coverredDistance;
	
	private GestureDetector detector;
	private GestureListener listener;
	
	boolean zoomStarted = false;
	
	
	public GestureFilter(Activity context, GestureListener hgl){
		detector = new GestureDetector(context,this);
		listener = hgl;
	}	

	/**
	 * This event handler observes the PinchZoom. PinchZoom is only detected if the second finger on the display has traveled
	 * more than 50 pixels. This ensures that there is no zoom when you just tap the display with both fingers. Because the
	 * Display isn't that accurate, there will always be a bit of movement. This will trigger the PinchZoom after approximately
	 * 2-3 seconds, which is  very intuitive for the user.
	 * 
	 * @param event Motion event that was triggered
	 * @return true if the GestureDetector.OnGestureListener consumed the event, else false. 
	 */
	public boolean onTouchEvent(MotionEvent event) {
		switch(event.getAction() & MotionEvent.ACTION_MASK){
			case MotionEvent.ACTION_POINTER_DOWN:
				oldDist = Math.sqrt(Math.pow(event.getX(0) - event.getX(1),2) + 
							Math.pow(event.getY(0) - event.getY(1),2));
				if (oldDist > 5.0) {
					mode = ZOOM;
				}
				coverredDistance = 0;
				break;
			case MotionEvent.ACTION_MOVE:
				if (mode == ZOOM) {
					newDist = Math.sqrt(Math.pow(event.getX(0) - event.getX(1),2) + 
		   						Math.pow(event.getY(0) - event.getY(1),2));
					 coverredDistance += Math.abs(newDist - oldDist);					 

					 oldDist = Math.sqrt(Math.pow(event.getX(0) - event.getX(1),2) + 
		   						Math.pow(event.getY(0) - event.getY(1),2));
					 break; 
				 }
			case MotionEvent.ACTION_POINTER_UP:
				if(zoomStarted){
					coverredDistance = 0;
					zoomStarted = false;
				}
				mode = NONE;
				break;
		}
		return detector.onTouchEvent(event); 
	}
	
	
	 /*
	  * (non-Javadoc)
	  * @see android.view.GestureDetector.SimpleOnGestureListener#onFling(android.view.MotionEvent, android.view.MotionEvent, float, float)
	  */
	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
		
		//ensure there is only one finger on the display to avoid errors
		 if(e1.getPointerCount() == 1){
			if ((float) Math.sqrt(Math.pow(e1.getX() -  e2.getX(),2)  + Math.pow(e1.getY() - e2.getY(),2)) > min_dist) { 
		
				//swipe left
				if(e1.getX() > e2.getX() && (Math.abs(e1.getX()-e2.getX()) > min_dist) ){
					if( Math.abs(e1.getY()-e2.getY()) > min_dist ) {						
						if( e1.getY() > e2.getY() ){
							listener.onSwipe(SWIPE_TOPLEFT);
							return true;
						}
						else{
							listener.onSwipe(SWIPE_BOTTOMLEFT);
							return true;
						}
					}
					else{
						listener.onSwipe(SWIPE_LEFT);
						return true;
					}												
				}
				//swipe right
				else if(e1.getX() < e2.getX() && Math.abs(e1.getX()-e2.getX()) > min_dist){
					if( (Math.abs(e1.getY()-e2.getY()) > min_dist) ) {
						if(e1.getY() > e2.getY()){
							listener.onSwipe(SWIPE_TOPRIGHT);
							return true;
						}else{
							listener.onSwipe(SWIPE_BOTTOMRIGHT);
							return true;
						}
					}
					else{
						listener.onSwipe(SWIPE_RIGHT);
						return true;
					}
				}
				//swipe up/down
				else if(Math.abs(e1.getY()-e2.getY()) > min_dist){
					if(e1.getY() > e2.getY()){
						listener.onSwipe(SWIPE_UP);
						return true;
					}else{
						listener.onSwipe(SWIPE_DOWN);
						return true;
					}		
				}
			}
		 }
		return false; 
	}	
	
	/**
	 * Specifies which functions have to be implemented to to use onSwipe and onPichZoom.
	 * 
	 */
	public static interface GestureListener{
		void onSwipe(int direction);
	}

}
